home *** CD-ROM | disk | FTP | other *** search
/ Aminet 4 / Aminet 4 - November 1994.iso / aminet / dev / c / cweb31p9d.lha / CWeb / examples / primes.w < prev    next >
Text File  |  1994-04-02  |  22KB  |  485 lines

  1. % PRIMES example of WEB/CWEB portability.  This documentation was
  2. % originally published in the article ``Literate Programming'' by Donald
  3. % E. Knuth in ``The Computer Journal'', May 1984, and later in the book
  4. % ``Literate Programming'', October 1991, where it appeared as the first
  5. % example of WEB programming for Pascal.  It has been translated into
  6. % CWEB by Andreas Scherer to show the ease of portability between
  7. % Pascal/WEB and C/CWEB.  As little changes as possible were made, so that
  8. % the section numbering of the Pascal and the C version are identical,
  9. % except that a small list of related literature was appended at the end.
  10. % Minor changes to include extra C functionality are mentioned in the text
  11. % that follows.  The `cite' feature of CWEB 2.8 is used.
  12.  
  13. % This program is distributed WITHOUT ANY WARRANTY, express or implied.
  14. % WEB Version --- Don Knuth, 1986
  15. % CWEB Version --- Andreas Scherer, 1993
  16.  
  17. % Copyright (c) 1993 Andreas Scherer
  18.  
  19. % Permission is granted to make and distribute verbatim copies of this
  20. % document provided that the copyright notice and this permission notice
  21. % are preserved on all copies.
  22.  
  23. % Permission is granted to copy and distribute modified versions of this
  24. % document under the conditions for verbatim copying, provided that the
  25. % entire resulting derived work is distributed under the terms of a
  26. % permission notice identical to this one.
  27.  
  28. \font\csc=cmcsc10
  29. \def\PASCAL/{{\csc Pascal\spacefactor1000}}
  30. \def\[{\ifhmode\ \fi$[\mkern-2mu[$}
  31. \def\]{$]\mkern-2mu]$\ }
  32. \def\Section{\mathhexbox278}
  33. \hyphenation{Dijk-stra}
  34.  
  35. \def\title{PRIMES (C Version 1.1)}
  36. \def\topofcontents{\null\vfill
  37.   \centerline{\titlefont Printing prime numbers}
  38.   \vskip15pt
  39.   \centerline{(C Version 1.1)}
  40.   \vfill}
  41. \def\botofcontents{\vfill
  42.   \noindent Copyright \copyright\ 1993 Andreas Scherer
  43.   \bigskip
  44.   \noindent Permission is granted to make and distribute verbatim copies of
  45.   this document provided that the copyright notice and this permission
  46.   notice are preserved on all copies.
  47.   \smallskip
  48.   \noindent Permission is granted to copy and distribute modified versions
  49.   of this document under the conditions for verbatim copying, provided that
  50.   the entire resulting derived work is distributed under the terms of a
  51.   permission notice identical to this one.}
  52.  
  53. @* Printing primes: An example of {\tt CWEB}. The following program is
  54. essentially the same as Edsger Dijkstra's@^Dijkstra, Edsger@> ``first
  55. example of step-wise program composition,'' found on pages 26--39 of his
  56. {\sl Notes on Structured Programming\/} [1], as presented by Donald E.
  57. Knuth@^Knuth, Donald E.@> on pages 103--112 of his {\sl Literate
  58. Programming\/} [2], but it has been translated into the \.{CWEB} language
  59. by Andreas Scherer@^Scherer, Andreas@>.
  60. @.CWEB@>@.WEB@>
  61.  
  62. \[Double brackets will be used in what follows to enclose comments relating
  63. to \.{CWEB} itself, because the chief purpose of this program is to introduce
  64. the reader to the \.{CWEB} style of documentation. \.{CWEB} programs are always
  65. broken into small sections, each of which has a serial number; the present
  66. section is number 1.\]
  67.  
  68. Dijkstra's program prints a table of the first thousand prime numbers. We
  69. shall begin as he did, by reducing the entire program to its top-level
  70. description. \[Every section in a \.{CWEB} program begins with optional {\it
  71. commentary\/} about that section, and ends with optional {\it program
  72. text\/} for the section. For example, you are now reading part of the
  73. commentary in \Section1, and the program text for \Section1 immediately
  74. follows the present paragraph. Program texts are specifications of \CEE/ 
  75. programs; they either use \CEE/ language directly, or they use angle brackets
  76. to represent \CEE/ code that appears in other sections. For example, the
  77. angle-bracket notation `|@<Program to print...@>|' is \.{CWEB}'s way of saying
  78. the following: ``The \CEE/ text to be inserted here is called `Program to
  79. print $\ldots$ numbers', and you can find out all about it by looking at
  80. section 2.'' One of the main characteristics of \.{CWEB} is that different
  81. parts of the program are usually abbreviated, by giving them such an
  82. informal top-level description.\]
  83.  
  84. @c
  85. @<Program to print the first thousand prime numbers@>
  86.  
  87. @ This program has no input, because we want to keep it rather simple. The
  88. result of the program will be to produce a list of the first thousand prime
  89. numbers, and this list will appear on the |stdout| file.
  90.  
  91. Since there is no input, we declare the value |MM==1000| as a compile-time
  92. constant. The program itself is capable of generating the first |MM| prime
  93. numbers for any positive |MM|, as long as the computer's finite limitations
  94. are not exceeded. The boolean values |TRUE| and |FALSE| are defined.
  95.  
  96. \[The program text below specifies the ``expanded meaning'' of `|@<Program
  97. to print...@>|'; notice that it involves the top-level descriptions of two
  98. other sections. When those top-level descriptions are replaced by their
  99. expanded meanings, a syntactically correct \CEE/ program will be obtained.\]
  100.  
  101. @d MM    1000
  102. @d TRUE     1
  103. @d FALSE    0
  104.  
  105. @<Program to print...@>=
  106. #include <stdio.h>
  107.  
  108. void main(void)
  109.    {
  110.    @<Variables of the program@>@;@#
  111.  
  112.    @<Print the first |MM| prime numbers@>@;
  113.    }
  114.  
  115. @* Plan of the program. We shall proceed to fill out the rest of the
  116. program by making whatever decisions seem easiest at each step; the idea
  117. will be to strive for simplicity first and efficiency later, in order to
  118. see where this leads us. The final program may not be optimum, but we want
  119. it to be reliable, well motivated, and reasonably fast.
  120.  
  121. Let us decide at this point to maintain a table that includes all of the
  122. prime numbers that will be generated, and to separate the generation
  123. problem from the printing problem.
  124.  
  125. \[The \.{CWEB} description you are reading once again follows a pattern that
  126. will soon be familiar: A typical section begins with comments and ends with
  127. program text. The comments motivate and explain noteworthy features of the
  128. program text.\]
  129.  
  130. @<Print the first...@>=
  131.    @<Fill table |p| with the first |MM| prime numbers@>@;
  132.    @<Print table |p|                                 @>@;
  133.  
  134. @ How should table |p| be represented? Two possibilities suggest
  135. themselves: We could construct a sufficiently large array of boolean values
  136. in which the |k|th entry is |TRUE| if and only if the number |k| is prime;
  137. or we could build an array of integers in which the |k|th entry is the
  138. |k|th prime number. Let us choose the latter alternative, by introducing an
  139. integer array called |p[MM]|.
  140.  
  141. In the documentation below, the notation `|p[k]|' will refer to the |k|th
  142. element of array |p|, while `$p_k$' will refer to the |k|th prime number.
  143. If the program is correct, |p[k-1]| will either be equal to $p_k$ or it
  144. will not yet have been assigned any value. (Note that arrays in \CEE/ are
  145. indexed starting from 0 and not from 1 as in \PASCAL/)
  146. @^Differences between \PASCAL/ and \CEE/@>
  147.  
  148. \[Incidentally, our program will eventually make use of several more
  149. variables as we refine the data structures. All of the sections where
  150. variables are declared will be called `|@<Variables of...@>|'; the
  151. number `4' in this name refers to the present section, which is the first
  152. section to specify the expanded meaning of `|@<Variables of...@>|'.
  153. The note `{\eightrm See also~$\ldots$}' refers to all of the other sections
  154. that have the same top-level description. The expanded meaning of
  155. `|@<Variables of...@>|' consists of all the program texts for this name,
  156. not just the text found in \Section4.\]
  157.  
  158. @<Variables of the program@>=
  159.    int p[MM]; /* the first |MM| prime numbers, in increasing order */
  160.  
  161. @* The output phase. Let's work on the second part of the program first.
  162. It's not as interesting as the problem of computing prime numbers; but the
  163. job of printing must be done sooner or later, and we might as well do it
  164. sooner, since it will be good to have it done. \[And it is easier to learn
  165. \.{CWEB} when reading a program that has comparatively few distracting
  166. complications.\]
  167.  
  168. Since |p| is simply an array of integers, there is little difficulty in
  169. printing the output, except that we need to decide upon a suitable output
  170. format. Let us print the table on separate pages, with |RR| rows and |CC|
  171. columns per page, where every column is |WW| character positions wide. In
  172. this case we shall choose |RR==50|, |CC==5|, and |WW==10|, so that
  173. the first 1000~primes will appear on four pages. The program will not assume
  174. that |MM| is an exact multiple of |RR@t${}\times{}$@>CC|.
  175. @^output format@>
  176. @^Differences between \PASCAL/ and \CEE/@>
  177.  
  178. @d RR 50 /* this many rows will be on each page in the output         */
  179. @d CC  5 /* this many columns will be on each page in the output      */
  180. @d WW 10 /* this many character positions will be used in each column */
  181.  
  182. @ In order to keep this program reasonably free of notations that are
  183. uniquely \CEE/esque, \[and in order to illustrate more of the facilities of
  184. \.{CWEB},\] a few macro definitions for low-level output instructions are
  185. introduced here. All of the output-oriented commands in the remainder of
  186. the program will be stated in terms of five simple primitives called
  187. |print_string|, |print_integer|, |print_entry|, |new_line|, and |new_page|.
  188.  
  189. \[Sections of a \.{CWEB} program are allowed to contain {\it macro
  190. definitions} between the opening comments and the closing program text. The
  191. general format for each section is actually tripartite: commentary, then
  192. definitions, then program. Any of the three parts may be absent; for
  193. example, the present section contains no program text.\]
  194.  
  195. \[Simple macros simply substitute a bit of \CEE/ code for an identifier.
  196. Parametric macros are similar, but they also substitute an argument
  197. wherever `A' occurs in the macro definition. (You may \#|define| macros with
  198. more than just one parameter in \CEE/.) The first three macro definitions
  199. here are parametric; the other two are simple. (I am using |fputs| in order
  200. to get rid of the surplus `new line' character inserted by |puts|, and I am
  201. using |putc| instead of |putchar| for consistency in notation.)\]
  202. @^Differences between \PASCAL/ and \CEE/@>
  203.  
  204. @d print_string(A)
  205.    fputs(A,stdout) /* put a given string into the |stdout| file */
  206. @d print_integer(A)
  207.    printf("%d",A) /* put a given integer into the |stdout| file, in decimal
  208.    notation, using only as many digit positions as necessary */
  209. @d print_entry(A)
  210.    printf("%*d",WW,A) /* like |print_integer|, but |WW| character positions
  211.    are filled, inserting blanks at the left */
  212. @d new_line putc('\n',stdout); fflush(stdout)
  213.    /* advance to a new line in the |stdout| file */
  214. @d new_page putc('\f',stdout); fflush(stdout)
  215.    /* advance to a new page in the |stdout| file */
  216.  
  217. @ Several variables are needed to govern the output process. When we begin
  218. to print a new page, the variable |page_number| will be the ordinal number
  219. of that page, and |page_offset| will be such that |p[page_offset-1]| is the
  220. first prime to be printed. Similarly, |p[row_offset-1]| will be the first
  221. prime in a given row.
  222.  
  223. \[Notice the notation `$\mathrel+\E$' below; this indicates that the present
  224. section has the same name as a previous section, so the program text will
  225. be appended to some text that was previously specified.\]
  226.  
  227. @<Variables of the program@>=
  228.    int page_number;
  229.       /* one more than the number of pages printed so far */
  230.    int page_offset;
  231.       /* index into |p| for the first entry on the current page */
  232.    int row_offset;
  233.       /* index into |p| for the first entry in the current row */
  234.    int c;
  235.       /* runs through the columns in a row (|0@t${}\ldots{}$@>CC|) */
  236.  
  237. @ Now that appropriate auxiliary variables have been introduced, the
  238. process of outputting table |p| almost writes itself.
  239.  
  240. @<Print table |p|@>={
  241.    page_number = page_offset = 1;
  242.    while(page_offset <= MM) {
  243.       @<Output a page of answers@>@;
  244.       page_number++;
  245.       page_offset += RR*CC;
  246.       }
  247.    }
  248.  
  249. @ A simple heading is printed at the top of each page.
  250. @^output format@>
  251. @^page headings@>
  252. @<Output a page of answers@>={
  253.    print_string("The First ");@+               print_integer(MM);
  254.    print_string(" Prime Numbers --- Page ");@+ print_integer(page_number);
  255.    new_line;@+ new_line; /* there's a blank line after the heading */
  256.    for(row_offset = page_offset; row_offset <= page_offset + RR - 1;
  257.       row_offset++)
  258.       @<Output a line of answers@>@;
  259.    new_page;
  260.    }
  261.  
  262. @ The first row will contain
  263. $$
  264.   p[1-1],\thinspace p[1+\.{RR}-1],\thinspace
  265.   p[1+2\cdot\.{RR}-1],\thinspace \ldots;
  266. $$
  267. a similar pattern holds for each value of the |row_offset|.
  268.  
  269. @<Output a line of answers@>={
  270.    for(c=0; c<=CC-1; c++) {
  271.       if(row_offset+c*RR <= MM)
  272.          print_entry(p[row_offset + c*RR -1]);
  273.       }
  274.    new_line;
  275.    }
  276.  
  277. @* Generating the primes. The remaining task is to fill table |p| with the
  278. correct numbers. Let us do this by generating its entries one at a time:
  279. Assuming that we have computed all primes that are |j| or less, we will
  280. advance |j| to the next suitable value, and continue doing this until the
  281. table is completely full.
  282.  
  283. The program includes a provision to initialize the variables in certain
  284. data structures that will be introduced later.
  285.  
  286. @<Fill table |p| with...@>=
  287.    @<Initialize the data structures@>@;
  288.    while(k < MM) {
  289.       @<Increase |j| until it is the next prime number@>@;
  290.       k++;@+ p[k-1] = j;
  291.       }
  292.  
  293. @ We need to declare the two variables |j| and |k| that were just
  294. introduced.
  295.  
  296. @<Variables of the...@>=
  297.    int j; /* all primes ${}\leq j$ are in table |p|                    */
  298.    int k; /* this many primes are in table |p| (|0@t${}\ldots{}$@>MM|) */
  299.  
  300. @ So far we haven't needed to confront the issue of what a prime number is.
  301. But everything else has been taken care of, so we must delve into a bit of
  302. number theory now.
  303.  
  304. By definition, a number is called prime if it is an integer greater than 1
  305. that is not evenly divisible by any smaller prime number. Stating this
  306. another way, the integer $j>1$ is not prime if and only if there exists a
  307. prime number $p_n<j$ such that |j| is a multiple of $p_n$.
  308. @^prime number, definition of@>
  309.  
  310. Therefore the section of the program that is called `|@<Increase |j|...@>|'
  311. could be coded very simply: `|do { j++; @<Give to...@> } while(!j_prime)@;|'.
  312. And to compute the boolean value |j_prime|, the following would suffice:
  313. `|j_prime=TRUE; for(n=1; n<=k; n++) @<If |p[n-1]|...@>@;|'.
  314.  
  315. @ However, it is possible to obtain a much more efficient algorithm by
  316. using more facts of number theory. In the first place, we can speed things
  317. up a bit by recognizing that $p_1=2$ and that all subsequent primes are
  318. odd; therefore we can let |j| run through odd values only. Our Program now
  319. takes the following form:
  320.  
  321. @<Increase...@>=
  322.    do@+ {
  323.       j += 2;
  324.       @<Update variables that depend on |j|                 @>@;
  325.       @<Give to |j_prime| the meaning: |j| is a prime number@>@;
  326.       }@+ while(!j_prime);
  327.  
  328. @ The |do| loop in the previous section introduces a boolean variable
  329. |j_prime|, so that it will not be necessary to resort to a |goto|
  330. statement. (We are following Dijkstra~[1], not Knuth~[3].)
  331. @^Dijkstra, Edsger@>
  332. @^Knuth, Donald E.@>
  333.  
  334. @<Variables...@>=
  335.    unsigned char j_prime; /* is |j| a prime number? */
  336.  
  337. @ In order to make the odd-even trick work, we must of course initialize
  338. the variables |j|, |k|, and |p[0]| as follows.
  339.  
  340. @<Initialize...@>=
  341.    j = k = 1;@+ p[0] = 2;
  342.  
  343. @ Now we can apply more number theory in order to obtain further economies.
  344. If |j| is not prime, its smallest prime factor $p_n$ will be $\sqrt{j}$ or
  345. less. Thus if we know a number |ord| such that
  346. $$
  347.   p[ord-1]^2>j,
  348. $$
  349. and if |j| is odd, we need only test for divisors in the set
  350. $\{$|p[1]|$,\ldots,$|p[ord-2]|$\}$. This is much faster than testing
  351. divisibility by the full set $\{$|p[1]|$,\ldots,$|p[k-1]|$\}$, since |ord|
  352. tends to be much smaller than |k|. (Indeed, when |k| is large, the celebrated
  353. ``prime number theorem'' implies that the value of |ord| will be approximately
  354. $2\sqrt{k}/{\rm ln}k$.)
  355.  
  356. Let us therefore introduce |ord| into the data structure. A moment's
  357. thought makes it clear that |ord| changes in a simple way when |j|
  358. increases, and that another variable |square| facilitates the updating
  359. process.
  360.  
  361. @<Variables...@>=
  362.    int ord; /* the smallest index ${}\geq2$ such that $p^2_{ord}>j$ */
  363.    int square; /* |square|${}=p^2_{ord}$ */
  364.  
  365. @ @<Initialize...@>=
  366.    ord=2;@+ square=9;
  367.  
  368. @ The value of |ord| will never get larger than a certain value |ORD_MAX|,
  369. which must be chosen sufficiently large. It turns out that |ord| never
  370. exceeds 30 when |MM==1000|.
  371.  
  372. @d ORD_MAX 30 /* $p^2_{ord\_max}$ must exceed $p_M$ */
  373.  
  374. @ When |j| has been increased by 2, we must increase |ord| by unity when
  375. $j=p^2_{ord}$, i.e., when |j==square|.
  376.  
  377. @<Update variables that depend on |j|@>=
  378.    if(j==square) {
  379.       ord++;@+ @<Update variables that depend on |ord|@>@;
  380.       }
  381.  
  382. @ At this point in the program, |ord| has just been increased by unity, and
  383. we want to set |square@t${}=p^2_{ord}$@>|. A surprisingly subtle point arises
  384. here: How do we know that $p_{ord}$ has already been computed, i.e., that
  385. |ord<=k|? If there were a gap in the sequence of prime numbers, such
  386. that $p_{k+1}>p^2_k$ for some |k|, then this part of the program would refer to
  387. the yet-uncomputed value |p[k]| unless some special test were made.
  388.  
  389. Fortunately, there are no such gaps. But no simple proof of this fact is
  390. known. For example, Euclid's famous demonstration that there are infinitely
  391. many prime numbers is strong enough to prove only that $p_{k+1}\leq
  392. p_1\ldots p_k+1$. Advanced books on number theory come to our rescue by
  393. showing that much more is true; for example, ``Bertrand's postulate''
  394. states that $p_{k+1}<2p_k$ for all $k$.
  395. @^Bertrand, Joseph, postulate@>
  396. @^Euclid@>
  397.  
  398. @<Update variables that depend on |ord|@>=
  399.    square = p[ord-1]*p[ord-1]; /* at this point |ord<=k| */
  400.  
  401. @* The inner loop. Our remaining task is to determine whether or not a
  402. given integer |j| is prime. The general outline of this part of the program
  403. is quite simple, using the value of |ord| as described above.
  404.  
  405. @<Give to...@>=
  406.    n = 2;@+ j_prime = TRUE;
  407.    while((n<ord) && j_prime) {
  408.       @<If |p[n-1]| is a factor of |j|, set |j_prime=FALSE|@>@;
  409.       n++;
  410.       }
  411.  
  412. @ @<Variables...@>=
  413.    int n; /* runs from 2 to |ord| when testing divisibility */
  414.  
  415. @ Let's suppose that division is very slow or nonexistent on our machine.
  416. We want to detect nonprime odd numbers, which are odd multiples of the set
  417. of primes $\{p_2,\ldots,p_{ord-1}\}$.
  418.  
  419. Since |ORD_MAX| is small, it is reasonable to maintain an auxiliary table
  420. of the smallest odd multiples that haven't already been used to show that
  421. some |j| is nonprime. In other words, our goal is to ``knock out'' all of
  422. the odd multiples of each $p_n$ in the set $\{p_2,\ldots,p_{ord-1}\}$, and
  423. one way to do this is to introduce an auxiliary table that serves as a
  424. control structure for a set of knock-out procedures that are being
  425. simulated in parallel. (The so-called ``sieve of Eratosthenes'' generates
  426. primes by a similar method, but it knocks out the multiples of each prime
  427. serially.)
  428. @^Eratosthenes, sieve of@>
  429.  
  430. The auxiliary table suggested by these considerations is a |mult| array that
  431. satisfies the following invariant condition: For $2\leq n<ord$, |mult[n-1]|
  432. is an odd multiple of $p_n$ such that |mult[n-1]@t${}<j+2p_n$@>|.
  433.  
  434. @<Variables...@>=
  435.    int mult[ORD_MAX]; /* runs through multiples of primes */
  436.  
  437. @ When |ord| has been increased, we need to initialize a new element of the
  438. |mult| array. At this point |j==p[ord-2]@t$^2$@>|, so there is no need for an
  439. elaborate computation.
  440.  
  441. @<Update variables that depend on |ord|@>=
  442.    mult[ord-2]=j;
  443.  
  444. @ The remaining task is straightforward, given the data structures already
  445. prepared. Let us recapitulate the current situation: The goal is to test
  446. whether or not |j| is divisible by $p_n$, without actually performing a
  447. division. We know that |j| is odd, and that |mult[n-1]| is an odd multiple
  448. of $p_n$ such that |mult[n-1]<j+2@t$p_n$@>|. If |mult[n-1]<j|, we can
  449. increase |mult[n-1]| by $2p_n$ and the same conditions will hold. On the
  450. other hand if |mult[n-1]<=j|, the conditions imply that |j| is
  451. divisible by $p_n$ if and only if |j==mult[n-1]|.
  452.  
  453. @<If |p[n-1]|...@>=
  454.    while(mult[n-1]<j)
  455.       mult[n-1] += 2*p[n-1];
  456.    if(mult[n-1]==j)
  457.       j_prime=FALSE;
  458.  
  459. @* For further reading. Here is a very short list of literature that has
  460. been mentioned in this text. A full reference can be found in [2].
  461. {\frenchspacing\parindent=1cm
  462. \bigskip
  463. \item{[1]} Ole-Johan Dahl, Edsger W. Dijkstra, and C. A. R. Hoare, {\sl
  464. Structured programming\/} (London: Academic Press, 1972), 220 pp.
  465. \item{[2]} Donald E. Knuth, {\sl Literate Programming\/} (Leland Stanford
  466. Junior University, 1992), 368 pp.
  467. \item{[3]} Donald E. Knuth, ``Structured programming with {\bf go to}
  468. statements,'' {\sl Computing Surveys\/} {\bf 6}, 4 (December 1974),
  469. 261--301. (Reprinted as chapter 2 of [2])\par}
  470.  
  471. @* Index. Every identifier used in this program is shown here together with
  472. a list of the section numbers where that identifier appears. The section
  473. number is underlined if the identifier was defined in that section.
  474. However, one-letter identifiers are indexed only at their point of
  475. definition, since such identifiers tend to appear almost everywhere. \[An
  476. index like this is prepared automatically by the \.{CWEB} software, and it is
  477. appended to the final section of the program.\]
  478.  
  479. This index also refers to some of the places where key elements of the
  480. program are treated. For example, the entries for `output format' and `page
  481. headings' indicate where details of the output format are discussed.
  482. Several other topics that appear in the documentation (e.g., `Bertrand's
  483. postulate') have also been indexed. \[Special instructions within a \.{CWEB}
  484. source file can be used to insert essentially anything into the index.\]
  485.